var Utils = require('geoUtils');
var InputTypeEnum = require('geoInputTypeEnum');
/**
 * 单例组件
 * UI管理器，通过它创建各种通用界面元素
 */
var UIManager = cc.Class({
    extends: cc.Component,

    properties: {
        uiRoot: {
            default: null,
            type: cc.Node,
            tooltip: '默认的ui根节点，不指定则使用场景下第一个Canvas所在节点',
        },
        maskPrefab: {
            default: null,
            type: cc.Prefab,
            tooltip: '用于弹出式模态类元素的背景遮罩',
        },
        dialogPrefab: {
            default: null,
            type: cc.Prefab,
            tooltip: '用于对话框的预制'
        },
        topBarPrefab: {
            default: null,
            type: cc.Prefab,
            tooltip: '顶部栏预制'
        },
        inputPrefab: {
            default: null,
            type: cc.Prefab,
            tooltip: '输入预制'
        },
        inputMiniPrefab: {
            default: null,
            type: cc.Prefab,
            tooltip: '迷你键盘预制'
        },
        inputMiniPlusPrefab: {
            default: null,
            type: cc.Prefab,
            tooltip: '迷你键盘预制'
        },
    },

    statics: {
        Singleton: null,
    },

    // LIFE-CYCLE CALLBACKS:
    onLoad() {
        if (!UIManager.Singleton) {
            this._init();
        }
        else
            this.destroy();
    },
    _init() {
        //
        UIManager.Singleton = this;
        //
        this.Dialog = require('geoUIDialog');
        this.TopBar = require('geoTopBar');
    },
    /**
     * 显示一个界面
     * @param {cc.Prefab || cc.Node} uiPrefab 界面的预制类，或源模板
     * @param {bool || {r,g,b,a}} useMask 是否启用背景遮罩，阻止后面的元素响应用户交互
     * @param {cc.Node} uiRoot 界面的父节点
     */
    open(uiPrefab, useMask, uiRoot) {
        useMask = useMask || false;
        uiRoot = uiRoot || this.getUIRoot();
        //
        var ui = null;
        if (uiPrefab != null)
            ui = cc.instantiate(uiPrefab);
        else
            ui = new cc.Node('NoNameUIOpenNode');
        // 若需要遮罩，先把遮罩加入层
        if (useMask !== false) {
            var mask = cc.instantiate(this.maskPrefab);
            if (useMask instanceof Object) {
                var maskColor = mask.color;
                maskColor.setR((useMask.r != null) ? useMask.r : maskColor.getR());
                maskColor.setG((useMask.g != null) ? useMask.g : maskColor.getG());
                maskColor.setB((useMask.b != null) ? useMask.b : maskColor.getB());
                //
                mask.color = maskColor;
                mask.opacity = (useMask.a != null) ? useMask.a : mask.opacity;
            }
            mask.parent = uiRoot;
            // 记录遮罩
            ui.uiMask = mask;
        }
        //
        ui.parent = uiRoot;
        //
        return ui;
    },
    /**
     * 
     * @param {NULL || {r,g,b,a}} mask 指定遮罩层颜色，默认黑，半透明
     * @param {NULL || cc.Node} uiRoot 遮罩层父节点，默认整个画面
     */
    openMask(mask, uiRoot) {
        mask = mask || true;
        return this.open(null, mask, uiRoot);
    },
    /**
     * 对指定节点的交互进行屏蔽。
     * 节点尺寸必须足够大以覆盖所有子节点的交互区域。
     * @param {cc.Node} nodeToMask 被屏蔽的节点。
     * @param {bool} bMask true，屏蔽；false，取消屏蔽
     */
    maskInteraction(nodeToMask, bMask) {
        var inMask = this.isInMask(nodeToMask);
        //
        if (bMask == true && inMask == false) {
            // 若需要屏蔽，且目前未被屏蔽，则屏蔽它
            nodeToMask.__interactionMask = this.openMask({ a: 0 }, nodeToMask);
        } else if (bMask == false && inMask == true) {
            // 若不要屏蔽，且目前被屏蔽，则释放它
            this.close(nodeToMask.__interactionMask);
            nodeToMask.__interactionMask = null;
        }
    },
    /**
     * 判定节点是否正在被屏蔽
     * @param {*} node 
     * @returns {bool} true，处于被屏蔽；false，未被屏蔽
     */
    isInMask(node) {
        if (node.__interactionMask != null)
            return true;
        else
            return false;
    },
    /**
     * 关闭指定界面，相当于销毁界面
     * @param {cc.Node || cc.Component } ui 
     */
    close(ui) {
        if (ui instanceof cc.Component)
            ui = ui.node;
        ui.destroy();
        ui.uiMask && (ui.uiMask.destroy());
    },
    /**
     * 显示ui
     * @param {cc.Node} ui 
     * @param {bool} bShow true显示，false隐藏
     */
    show(ui, bShow) {
        if (ui instanceof cc.Component)
            ui = ui.node;
        //
        bShow = (bShow === undefined) ? true : bShow;
        ui.uiMask && (ui.uiMask.active = bShow);
        ui.active = bShow;
    },
    /**
     * 隐藏ui，不销毁
     * @param {cc.Node} ui 
     */
    hide(ui) {
        this.show(ui, false);
    },
    /**
     * 创建一个对话框
     * @param {bool} useMask 
     * @param {cc.Node} uiRoot 
     * @returns {Dialog} 被创建的Dialog上的Dialog组件，用于后续加工对话框
     */
    openDialog(useMask, uiRoot) {
        var baseNode = this.open(this.dialogPrefab, useMask, uiRoot);
        var com = baseNode.getComponent(this.Dialog);
        com.baseNode = baseNode;
        return com;
    },
    /**
     * 在界面顶部显示公共栏
     * 该方法调用后可通过uiManager.topBar直接使用
     */
    openTopBar() {
        if (this.topBar != null && this.topBar.isValid === true)
            return this.topBar;
        //
        var baseNode = this.open(this.topBarPrefab);
        this.topBar = baseNode.getComponent(this.TopBar);
        this.topBar.baseNode = baseNode;
        //
        return this.topBar;
    },
    /**
     * 打开迷你输入模块
     * @param {string} title 输入模块的标题
     * @param {string} input 输入模块默认值
     * @param {int} maxLength 输入模块最大字符长度
     * @param {function} onInput 每次输入回调，原型如下：
     * onInput(input, key)，input是目前所有输入，key是当前输入的值，可能为空
     * @param {function} onOK 输入结束回调，原型如下：
     * onOK(input)，input为最终输入值
     * @param {InputTypeEnum} inputType 使用的键盘类型
     */
    openInput(title, input, maxLength, onInput, onOK, inputType, uiRoot) {
        var inputPrefab = null;
        var useMini = true;
        switch (inputType) {
            case InputTypeEnum.BIG:
                inputPrefab = this.inputPrefab;
                useMini = false;
                break;
            case InputTypeEnum.MINI:
                inputPrefab = this.inputMiniPrefab;
                break;
            case InputTypeEnum.MINI_PLUS:
                inputPrefab = this.inputMiniPlusPrefab;
                break;
        }
        // 创建输入模块
        var inputModel = cc.instantiate(inputPrefab);
        // 先把inputModel当作inputDlg
        // 创建外围对话框
        var inputDlg = this.openDialog(true, uiRoot);
        if (useMini !== true) {
            // 组合
            inputDlg
                .setContentSize(inputModel.width, inputModel.height)
                .setContent(inputModel)
                .setTitle(title);
        } else {
            // 去除inputDlg所有内部件
            inputDlg.baseNode.removeAllChildren();
            // 加入输入模型
            inputDlg.baseNode.addChild(inputModel);
            //
            // inputModel.position = new cc.Vec2();
        }
        // 绑定事件方法
        var inputMethod = inputModel.getComponentInChildren('geoInputMethod');
        // 记录当前输入模组的根节点
        inputMethod.baseNode = inputDlg.baseNode;
        //
        inputMethod.input = input || '';
        // 设置可能存在的文本显示组件
        var textBlock = inputModel.getComponentInChildren('geoTextBlock');
        if (textBlock != null)
            textBlock.setText(inputMethod.input);
        //
        inputMethod.maxLength = maxLength || -1;
        inputMethod.onInput = (target, input, key) => {
            // 回调
            onInput && onInput(input, key);
        };
        inputMethod.onOK = ((target, input) => {
            // 回调
            onOK && onOK(input);
            // 销毁输入对话框
            this.close(inputDlg);
        }).bind(this);
        //
        if (useMini !== true) {
            // 另inputModel铺满
            var inputWidget = inputModel.getComponent(cc.Widget) || inputModel.addComponent(cc.Widget);
            // inputWidget = (inputWidget == null) ? inputModel.addComponent(cc.Widget) : inputWidget;
            inputWidget.isAlignTop = true;
            inputWidget.isAlignBottom = true;
            inputWidget.isAlignLeft = true;
            inputWidget.isAlignRight = true;
            inputWidget.top = 0;
            inputWidget.bottom = 0;
            inputWidget.left = 0;
            inputWidget.right = 0;
        }
        //
        return inputMethod;
    },
    /**
     * 渐变遮罩
     * @param {bool} inOrOut fade in or fade out
     * @param {*} duration 渐变时间
     * @param {*} color 渐变基色
     * @param {*} complete 渐变完成回调
     */
    fadeMask(inOrOut, duration, color, complete) {
        // 若时长小于0，则不做渐变处理
        if (duration <= 0) {
            complete && complete();
            return;
        }
        //
        color = color || cc.Color.BLACK;
        var uiRoot = this.getUIRoot();
        var mask = cc.instantiate(this.maskPrefab);
        mask.parent = uiRoot;
        //
        mask.color = color;
        mask.opacity = (inOrOut == true) ? 0 : 255;
        //
        var fadeAction =
            (inOrOut == true) ? cc.fadeIn(duration) : cc.fadeOut(duration);
        //
        mask.runAction(
            cc.sequence([
                fadeAction, cc.callFunc(() => {
                    mask.destroy();
                    complete && complete();
                })
            ]));
    },
    /**
     * 从透明显示遮罩层
     * @param {float} duration 渐变时长
     * @param {cc.Color} color 渐变基色
     * @param {Function} complete 渐变完成后调用
     */
    fadeMaskIn(duration, color, complete) {
        this.fadeMask(true, duration, color, complete);
    },
    /**
     * 将遮罩层显示至透明
     * @param {float} duration 渐变时长
     * @param {cc.Color} color 渐变基色
     * @param {Function} complete 渐变完成后调用
     */
    fadeMaskOut(duration, color, complete) {
        this.fadeMask(false, duration, color, complete);
    },
    /**
     * 将mask由透明渐变到不透明，再渐变到透明
     * 适合做画面衔接
     * @param {float} duration 渐变时长
     * @param {cc.Color} color 渐变基色
     * @param {Function} fadeInComplete fade in 完成后调用
     * @param {Function} fadeOutComplete fade out 完成后调用
     */
    fadeMaskInOut(duration, color, fadeInComplete, fadeOutComplete) {
        this.fadeMaskIn(duration, color, (() => {
            fadeInComplete && fadeInComplete();
            this.fadeMaskOut(duration, color, fadeOutComplete);
        }).bind(this));
    },
    getUIRoot() {
        // 若缓存已经无效，就放弃缓存
        this.uiRoot && (this.uiRoot.isValid != true) && (this.uiRoot = null);
        // 获取有效的节点作为ui父节点
        var root = this.uiRoot ||
            Utils.node.getNodesInHierarchyByNameMark(cc.director.getScene(), 'ui', 'overlay')[0] ||
            cc.director.getScene().getComponentInChildren(cc.Canvas).node;
        // 缓存以提高效率
        this.uiRoot = root;
        //
        return root;
    },
});

module.exports = UIManager;
